package com.youhome.service.service.impl;

import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.pingplusplus.Pingpp;
import com.pingplusplus.exception.*;
import com.pingplusplus.model.Charge;
import com.youhome.common.exception.CustomException;
import com.youhome.common.pingxx.PingxxData;
import com.youhome.common.response.ResultCode;
import com.youhome.service.model.BUser;
import com.youhome.service.model.Order;
import com.youhome.service.model.Principal;
import com.youhome.service.service.BUserService;
import com.youhome.service.service.OrderService;
import com.youhome.service.service.PayService;
import com.youhome.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.binary.Base64;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.math.BigDecimal;
import java.security.*;
import java.security.spec.X509EncodedKeySpec;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by chen365 on 2017/9/23.
 */
@Service
@Slf4j
public class PayServiceImpl implements PayService {

    @Autowired
    private OrderService orderService;
    @Autowired
    private BUserService userService;

    @Override
    public String scanCodePay(Order order, String ip, Integer credential) throws Exception {

        Pingpp.overrideApiBase(PingxxData.getApiBase());
        Pingpp.apiKey = PingxxData.getApiKey();
        // 建议使用 PKCS8 编码的私钥，可以用 openssl 将 PKCS1 转成 PKCS8
        Pingpp.privateKey = PingxxData.getPKCS8PrivateKey();
        Pingpp.DEBUG = true;

        String appId = PingxxData.getAppID();
        System.err.println("appid:" + appId);
        String orderno = order.getOrderno();
        Integer amount = order.getAmount().multiply(new BigDecimal(100)).intValue();

        System.err.println("amount:" + amount);
        String subject = order.getOrderItems().get(0).getProduct().getName();
        String body = "商品描述：" + order.getOrderItems().get(0).getProduct().getContent();

        String product_id = String.valueOf(order.getOrderItems().get(0).getProduct().getId());

        System.err.println("product_id:" + product_id);
        System.err.println("subject:" + subject);
        System.err.println("body:" + body);
        String channel = null;

        if (credential == 1) {
            channel = "alipay_qr";  //支付宝扫码
        } else if (credential == 2) {
            channel = "wx_pub_qr"; //微信扫码
        }
        String client_ip = ip;
        Charge charge = null;

        Map<String, Object> chargeMap = new HashMap<String, Object>();
        chargeMap.put("amount", amount);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        chargeMap.put("currency", "cny");
        chargeMap.put("subject", subject); //商品名
        chargeMap.put("body", body); //商品描述
        chargeMap.put("order_no", orderno);// 推荐使用 8-20 位，要求数字或字母，不允许其他字符
        chargeMap.put("channel", channel);// 支付使用的第三方支付渠道取值，请参考：https://www.pingxx.com/api#api-c-new
        chargeMap.put("client_ip", client_ip); // 发起支付请求客户端的 IP 地址，格式为 IPV4，如: 127.0.0.1

        Map<String, String> app = new HashMap<String, String>();
        app.put("id", appId);

        chargeMap.put("app", app);

        Map<String, Object> extra = new HashMap<String, Object>();
        //extra.put("success_url", "http://127.0.0.1/alipay/success");

        if (credential == 2) {
            extra.put("product_id", product_id);
        }
        chargeMap.put("extra", extra);

        try {
            // 发起 charge 创建请求
            charge = Charge.create(chargeMap);
            // 传到客户端请先转成字符串 .toString(), 调该方法，会自动转成正确的 JSON 字符串
            String chargeString = charge.toString();
            JsonObject jsonObject = new JsonParser().parse(chargeString).getAsJsonObject();

            return jsonObject.get("credential").getAsJsonObject().get(channel).getAsString();
//            if (credential == 1) {
//                return jsonObject.get("credential").getAsJsonObject().get("alipay_qr").getAsString();
//            } else if (credential == 2) {
//                return jsonObject.get("credential").getAsJsonObject().get("wx_pub_qr").getAsString();
//            }
        } catch (APIConnectionException e) {
            e.printStackTrace();
        } catch (ChannelException e) {
            e.printStackTrace();
        } catch (AuthenticationException e) {
            e.printStackTrace();
        } catch (APIException e) {
            e.printStackTrace();
        } catch (InvalidRequestException e) {
            e.printStackTrace();
        } catch (RateLimitException e) {
            e.printStackTrace();
        }

        return null;
    }

    @Override
    public String scanCodePay(Principal principal, String orderNo, String ip, Integer credential) throws CustomException {
        Order order = orderService.selectByOrderNo(principal, orderNo);

        if (order == null)
            throw new CustomException(ResultCode.ILLEGAL_OPERATION);
        BUser currentUser = userService.getCurrentUser();

        if (order.getUserId().longValue() != currentUser.getUserId().longValue())
            throw new CustomException(ResultCode.ILLEGAL_OPERATION);

        Pingpp.overrideApiBase(PingxxData.getApiBase());
        Pingpp.apiKey = PingxxData.getApiKey();
        // 建议使用 PKCS8 编码的私钥，可以用 openssl 将 PKCS1 转成 PKCS8
        Pingpp.privateKey = PingxxData.getPKCS8PrivateKey();
        Pingpp.DEBUG = true;

        String appId = PingxxData.getAppID();
        System.err.println("appid:" + appId);
        String orderno = order.getOrderno();
        Integer amount = order.getAmount().multiply(new BigDecimal(100)).intValue();

        System.err.println("amount:" + amount);
        String subject = order.getOrderItems().get(0).getProduct().getName();
        String body = "商品描述：" + order.getOrderItems().get(0).getProduct().getContent();

        String product_id = String.valueOf(order.getOrderItems().get(0).getProduct().getId());

        System.err.println("product_id:" + product_id);
        System.err.println("subject:" + subject);
        System.err.println("body:" + body);
        String channel = null;

        if (credential == 1) {
            channel = "alipay_qr";  //支付宝扫码
        } else if (credential == 2) {
            channel = "wx_pub_qr"; //微信扫码
        }
        String client_ip = ip;
        Charge charge = null;

        Map<String, Object> chargeMap = new HashMap<String, Object>();
        chargeMap.put("amount", amount);//订单总金额, 人民币单位：分（如订单总金额为 1 元，此处请填 100）
        chargeMap.put("currency", "cny");
        chargeMap.put("subject", subject); //商品名
        chargeMap.put("body", body); //商品描述
        chargeMap.put("order_no", orderno);// 推荐使用 8-20 位，要求数字或字母，不允许其他字符
        chargeMap.put("channel", channel);// 支付使用的第三方支付渠道取值，请参考：https://www.pingxx.com/api#api-c-new
        chargeMap.put("client_ip", client_ip); // 发起支付请求客户端的 IP 地址，格式为 IPV4，如: 127.0.0.1

        Map<String, String> app = new HashMap<String, String>();
        app.put("id", appId);

        chargeMap.put("app", app);

        Map<String, Object> extra = new HashMap<String, Object>();
        //extra.put("success_url", "http://127.0.0.1/alipay/success");

        if (credential == 2) {
            extra.put("product_id", product_id);
        }
        chargeMap.put("extra", extra);

        try {
            // 发起 charge 创建请求
            charge = Charge.create(chargeMap);
            // 传到客户端请先转成字符串 .toString(), 调该方法，会自动转成正确的 JSON 字符串
            String chargeString = charge.toString();
            JsonObject jsonObject = new JsonParser().parse(chargeString).getAsJsonObject();
            String url = jsonObject.get("credential").getAsJsonObject().get(channel).getAsString();
            if (StringUtils.isEmpty(url)) {
                throw new CustomException(ResultCode.FAIL_PAY);
            }
            return url;
//            if (credential == 1) {
//                return jsonObject.get("credential").getAsJsonObject().get("alipay_qr").getAsString();
//            } else if (credential == 2) {
//                return jsonObject.get("credential").getAsJsonObject().get("wx_pub_qr").getAsString();
//            }
        } catch (APIConnectionException e) {
            e.printStackTrace();
            throw new CustomException(ResultCode.FAIL);
        } catch (ChannelException e) {
            e.printStackTrace();
            throw new CustomException(ResultCode.FAIL);
        } catch (AuthenticationException e) {
            e.printStackTrace();
            throw new CustomException(ResultCode.FAIL);
        } catch (APIException e) {
            e.printStackTrace();
            throw new CustomException(ResultCode.FAIL);
        } catch (InvalidRequestException e) {
            e.printStackTrace();
            throw new CustomException(ResultCode.FAIL);
        } catch (RateLimitException e) {
            e.printStackTrace();
            throw new CustomException(ResultCode.FAIL);
        }
    }

    @Override
    public void alipaySuccess(HttpServletRequest request, HttpServletResponse response) throws IOException {
        // 获取event的json字符串
        StringBuffer sb = new StringBuffer();
        InputStream is = request.getInputStream();
        InputStreamReader isr = new InputStreamReader(is);
        BufferedReader br = new BufferedReader(isr);
        String s = "";
        while ((s = br.readLine()) != null) {
            sb.append(s);
        }
        String eventStr = sb.toString();

        request.setCharacterEncoding("UTF8");
        //获取头部所有信息
        Enumeration headerNames = request.getHeaderNames();
        String signature = null;
        while (headerNames.hasMoreElements()) {
            String key = (String) headerNames.nextElement();
            String value = request.getHeader(key);
            if ("x-pingplusplus-signature".equals(key)) {
                signature = value;
            }
        }

        log.info(signature);
        log.info(eventStr);


        boolean verifyRS = true;
        try {
            String publicKey = PingxxData.getPublicKey();
            System.out.println(publicKey);
            verifyRS = verifyData(eventStr, signature, getPubKey(publicKey));
        } catch (Exception e) {
            e.printStackTrace();
        }


        if (verifyRS) {
            System.out.println("签名验证成功");
            JsonObject event = new JsonParser().parse(eventStr).getAsJsonObject();
            if ("charge.succeeded".equals(event.get("type").getAsString())) {
                JsonObject data = new JsonParser().parse(event.get("data").toString()).getAsJsonObject();
                JsonObject object = new JsonParser().parse(data.get("object").toString()).getAsJsonObject();

                String orderId = object.get("order_no").getAsString();
                String channel = object.get("channel").getAsString();
                Integer payType = null;

                if ("alipay_qr".equals(channel)) {
                    payType = 1;
                } else if ("wx_pub_qr".equals(channel)) {
                    payType = 2;
                }
                Order order = null;
                try {
                    order = orderService.selectByOrderNo(orderId);
                    if (order != null) {
                        Boolean bool = orderService.orderPaySuccess(order, payType);
                        if (bool) {
                            System.out.println("订单结算成功");
                            response.setStatus(200);
                            //return "订单结算成功";
                        } else {
                            System.out.println("订单结算失败");
                            //return "订单结算失败";
                            response.setStatus(500);
                        }
                    } else {
                        System.out.println("该订单不存在");
                        //return "该订单不存在";
                        response.setStatus(500);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } else {
            System.out.println("签名验证失败");
            //return "签名验证失败";
            response.setStatus(500);
        }
    }


    /**
     * 获得公钥
     *
     * @return
     * @throws Exception
     */
    public static PublicKey getPubKey(String pubKey) throws Exception {
        String pubKeyString = pubKey.replaceAll("(-+BEGIN PUBLIC KEY-+\\r?\\n|-+END PUBLIC KEY-+\\r?\\n?)", "");
        pubKeyString = pubKeyString.replaceAll("\n", "");
//        System.err.println("==================================================");
//        System.err.println("pubKeyString:" + pubKeyString);
//        System.err.println("====================================================");
        byte[] keyBytes = Base64.decodeBase64(pubKeyString);

        // generate public key
        X509EncodedKeySpec spec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey publicKey = keyFactory.generatePublic(spec);
        return publicKey;
    }

    /**
     * 验证签名
     *
     * @param dataString
     * @param signatureString
     * @param publicKey
     * @return
     * @throws NoSuchAlgorithmException
     * @throws InvalidKeyException
     * @throws SignatureException
     */
    public static boolean verifyData(String dataString, String signatureString, PublicKey publicKey)
            throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, UnsupportedEncodingException {

        byte[] signatureBytes = Base64.decodeBase64(signatureString);
        Signature signature = Signature.getInstance("SHA256withRSA");
        signature.initVerify(publicKey);
        signature.update(dataString.getBytes("UTF-8"));

//        System.err.println("dataString:========>>" + dataString);
//        System.err.println("---------------------------------------------------------");
//        System.err.println("signatureString:===>>" + signatureString);
//        System.err.println("---------------------------------------------------------");
//        System.err.println("publicKey:=========>>" + publicKey.toString());
//        System.err.println("---------------------------------------------------------");
        return signature.verify(signatureBytes);
    }


}
